package it.valeandre.gollometro.net;


import it.valeandre.gollometro.model.TokenUpdate;
import it.valeandre.gollometro.utils.ResBundle;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.Reader;
import java.io.StringWriter;
import java.io.Writer;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.ThreadFactory;

import org.apache.http.HttpResponse;
import org.apache.http.HttpStatus;
import org.apache.http.StatusLine;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.params.HttpConnectionParams;
import org.codehaus.jackson.map.ObjectMapper;

import android.util.Log;


public class NetworkService {

	private static NetworkService mInstance;
	private ExecutorService mExecutor;

	public static NetworkService getInstance() {
		if (mInstance == null) {
			mInstance = new NetworkService();
		}
		return mInstance;
	}

	private NetworkService() {
		mExecutor = Executors.newFixedThreadPool(3, new ThreadFactory() {

			public Thread newThread(Runnable r) {
				Thread t = new Thread(r);
				t.setPriority(Thread.NORM_PRIORITY);
				return t;
			}
		});
	}

	private abstract class NetworkTask implements Runnable {

		protected NetworkServiceListener mListener;
		protected String mEndpoint;
		protected ObjectMapper mObjectMapper;
		protected DefaultHttpClient mClient;

		public NetworkTask(String endpoint, NetworkServiceListener listener) {
			mListener = listener;
			mEndpoint = endpoint;
			mObjectMapper = new ObjectMapper();
			mClient = new DefaultHttpClient();
			HttpConnectionParams.setConnectionTimeout(mClient.getParams(), 10000);
		}
		
		public void run() {
			runTask();
		}

		public abstract void runTask();
	}
	
	private class UpdatePushNotificationTokenTask extends NetworkTask {
		
		private TokenUpdate mTokenUpdate;

		public UpdatePushNotificationTokenTask(TokenUpdate tokenUpdate, NetworkServiceListener listener) {
			super(ResBundle.TOKEN_UPDATE_ENDPOINT, listener);
			mTokenUpdate = tokenUpdate;
		}

		@Override
		public void runTask() {
			HttpResponse response = null;

			try {
				HttpPost request = new HttpPost(mEndpoint);
				 
				Log.d("TAG", "" + mEndpoint);
				
				Writer strWriter = new StringWriter();
				mObjectMapper.writeValue(strWriter, mTokenUpdate);
				
				StringEntity se = new StringEntity(strWriter.toString());
				
				Log.d("TAG", "JSON: " + strWriter.toString());
				
				request.setEntity(se);
				request.addHeader("User-Agent", "android");
				request.addHeader("Content-Type", "application/json");
				response = mClient.execute(request);
				
				StatusLine status = response.getStatusLine();
				
				if (status.getStatusCode() == HttpStatus.SC_OK || status.getStatusCode() == HttpStatus.SC_NOT_MODIFIED) {
					Log.d("TAG", "Http status: " + status.getStatusCode());
					mListener.tokenUpdatePerformed(status.getStatusCode());
				}else {
					mListener.tokenUpdateFailed(status.getStatusCode());
					Log.d("TAG", "Http error: " + status.getStatusCode());
				}
				
			} catch (Exception e) {
				e.printStackTrace();
				mListener.tokenUpdateFailed(e);
				Log.d("TAG", "Error: " + e.toString());
			}
			
		}
		
	}

	public void updateToken(TokenUpdate token, NetworkServiceListener listener) {
		UpdatePushNotificationTokenTask task = new UpdatePushNotificationTokenTask(token, listener);
		mExecutor.execute(task);
	}
	
	public String convertStreamToString(InputStream is) throws IOException {
		
		if (is != null) {
			Writer writer = new StringWriter();

			char[] buffer = new char[1024];
			try {
				Reader reader = new BufferedReader(new InputStreamReader(is,
						"UTF-8"));
				int n;
				while ((n = reader.read(buffer)) != -1) {
					writer.write(buffer, 0, n);
				}
			} finally {
				is.close();
			}
			return writer.toString();
		} else {
			return "";
		}
	}
	
}
